home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / pc / files / pbbs / iosc51.arc / BR1BIOS.ASM next >
Assembly Source File  |  1988-02-15  |  19KB  |  657 lines

  1.         PAGE    60,132
  2.         TITLE   BR1BIOS - Serial interface for COM1
  3.  
  4. ;Interupt driven RS232 serial port routines.
  5. ; these routines replace the BIOS rs232 calls with a version that has
  6. ; interupt driven character receive, and can thus operate at considerably
  7. ;  higher speeds than the standard bios calls (int 14h).
  8. ; Added break function (7).
  9. ; Set up the works
  10.  
  11. everything SEGMENT PUBLIC
  12.       ASSUME CS: everything           ; These assumptions are for the
  13.       ASSUME DS: everything           ; assembler's benefit.  The code
  14.       ASSUME ES: nothing              ; jerks things around as it pleases
  15.       ASSUME SS: nothing
  16.  
  17. ; Program start and buffer declares
  18.  
  19.           ORG     100H
  20. foo:      jmp     start               ; Entry point
  21.  
  22.           org     0                   ; Back up so we can use this all as
  23.                                       ; buffer space
  24.  
  25. ; Area where things are declared
  26.  
  27.  include constbios.asm
  28.  
  29. dummy:                               ; Dummy labels to provide a structure
  30.  
  31. i_buf     db     buffer_size dup(?)  ; Buffer (1 per com card)
  32. i_buf_e:                             ; End of buffer
  33. comnumber db      ?                  ; Comm number - 1
  34. flags     db      ?                  ; Flag byte
  35. last_rs   db      ?                  ; Last receive status
  36. hiv       db      ?                  ; Hardware interrupt vector
  37. int_mask  db      ?                  ; Mask for 8259
  38. baseaddr  dw      ?                  ; Base port address
  39. i_count   dw      ?                  ; # of chars in buffer
  40. i_buf_in  dw      ?                  ; Buffer in pointer
  41. i_buf_out dw      ?                  ; Buffer out pointer
  42. dummy_end:
  43.  
  44.           org     dummy               ; Back up over this
  45.  
  46. ; These are the things to work with
  47.  
  48.  
  49.           db      buffer_size dup(?)  ; Buffer (1 per com card)
  50.           db      0                   ; Com number
  51.           db      0                   ; Flags
  52.           db      0                   ; Last receive status
  53.           db      0ch                 ; Hardware interrupt vector
  54.           db      0efh                ; Mask
  55.           dw      03f8h               ; Base port address
  56.           dw      0                   ; # of chars in buffer
  57.           dw      ?                   ; Buffer in pointer
  58.           dw      ?                   ; Buffer out pointer
  59.  
  60.  
  61. comend:                               ; Marker for last com port
  62.  
  63. ; Static variables
  64.  
  65. old_bios_vector   dw  ?            ; Save previous interrupt vector
  66.                   dw  ?
  67.  
  68. divisor_table LABEL WORD
  69.         dw      1047                ; 110
  70.         dw      768                 ; 150
  71.         dw      384                 ; 300
  72.         dw      192                 ; 600
  73.         dw      96                  ; 1200
  74.         dw      48                  ; 2400
  75.         dw      24                  ; 4800
  76.         dw      12                  ; 9600
  77.  
  78.  
  79. ; Our BIOS handler
  80.  
  81. rsint:
  82.  
  83.         ASSUME DS: NOTHING         ; Don't use DS
  84.         ASSUME ES: NOTHING         ; Don't use ES
  85.         ASSUME SS: NOTHING         ; Don't use SS
  86.  
  87. ; Not disabled please
  88.  
  89.         sti
  90.  
  91. ; See if this is our vector?
  92.  
  93.         push    bp                  ; Save BP over our loop
  94.         xor     bp,bp
  95.         cmp     dl,cs:comnumber[bp] ; Is this our port?
  96.         je      rsint_ours          ; Yes...
  97.  
  98. ; Not us.. Pop things out and call regular handler
  99.  
  100.         pop     bp
  101.         jmp     cs:dword ptr old_bios_vector
  102.  
  103. ; BP now contains the pointer to the com block...  See what
  104. ; the user has requested and we may or may not do it.......
  105.  
  106. rsint_ours:
  107.  
  108.         push    dx                  ; We need the DX register
  109.         push    cx                  ; We need the CX register
  110.         push    bx                  ; We need the BX register
  111.  
  112.         mov     cx,baseaddr[bp]     ; Get base address for chip
  113.  
  114.         or      ah,ah               ; Initialize?
  115.         je      rsint_init          ; Yes...
  116.  
  117.         dec     ah                  ; 1 = Send character
  118.         jz      rsint_send
  119.  
  120.         dec     ah                  ; 2 = Receive character
  121.         jz      rsint_recv_jmp
  122.  
  123.         dec     ah                  ; 3 = Status request
  124.         jz      rsint_status_jmp
  125.  
  126.         dec     ah                  ; 4 = Inquiry
  127.         jz      rsint_inquiry_jmp
  128.  
  129.         dec     ah
  130.         dec     ah
  131.         dec     ah
  132.         jz      rsint_break_jmp     ; 7 = send break
  133.  
  134.         jmp     rsint_exit          ;      Nope..
  135.  
  136. rsint_recv_jmp:
  137.         jmp     rsint_recv
  138. rsint_status_jmp:
  139.         jmp     rsint_status
  140. rsint_inquiry_jmp:
  141.         jmp     rsint_inquiry
  142. rsint_break_jmp:
  143.         jmp     rsint_break
  144.  
  145. ; Interrupt exit
  146.  
  147. rsint_exit:
  148.  
  149.         pop     bx                  ; Restore registers
  150.         pop     cx
  151.         pop     dx
  152.         pop     bp
  153.         iret                        ;      and leave
  154.  
  155. ; Init..
  156.  
  157. rsint_init:
  158.  
  159.  
  160.         mov     ah,al               ; Save the parms for later
  161.  
  162.         mov     bl,ah               ; Look up the baud rate
  163.         mov     cl,4                ; parameter
  164.         rol     bl,cl
  165.         and     bx,0eh
  166.         mov     bx,divisor_table[bx]
  167.  
  168.         mov     cx,baseaddr[bp]     ; Get base address for chip
  169.         mov     dx,cx               ; Address of LCR
  170.         add     dx,lcr_8250
  171.         mov     al,10000000B        ; Enable access to divisor
  172.         out     dx,al
  173.  
  174.         mov     dx,cx               ; Address of lower divisior half
  175.         add     dx,dll_8250
  176.         mov     al,bl               ; Put lower half
  177.         out     dx,al
  178.  
  179.         mov     dx,cx               ; Address of upper divisior half
  180.         add     dx,dlm_8250
  181.         mov     al,bh               ; Put upper half
  182.         out     dx,al
  183.  
  184.         mov     al,ah               ; Get parms back
  185.         and     al,1fh              ; Throw away baud rate
  186.         mov     dx,cx               ; Address of LCR
  187.         add     dx,lcr_8250
  188.         out     dx,al               ; Output the parms
  189.  
  190. ; Turn on the port
  191.  
  192.         mov     dx,cx             ; Compute port address for the MCR
  193.         add     dx,mcr_8250
  194.         mov     al,00001011B      ; Raise DTR, RTS  & OUT2
  195.         out     dx,al             ; OUT2 turns on interrupts
  196.  
  197.         jmp     rsint_status        ; Now just status please
  198.  
  199. ; Send a character
  200.  
  201. rsint_send:
  202.  
  203.         mov     ah,al               ; Save the character to send
  204.  
  205. rsint_send_loop:                    ; Loop here until we can send
  206.  
  207.         mov     dx,cx               ; Compute port address for the MSR
  208.         add     dx,msr_8250         ;      and then
  209.         in      al,dx               ;      get it into AX
  210.         and     al,10h              ; CTS
  211.         jz      rsint_send_loop
  212.  
  213.         mov     dx,cx               ; Compute port address for the LSR
  214.         add     dx,lsr_8250         ;      and then
  215.         in      al,dx               ;      get itinto AX
  216.         and     al,20h              ; THR empty?
  217.         jz      rsint_send_loop     ;      No.. Loop back
  218.  
  219.         mov     al,ah               ; Get ready to out character
  220.  
  221.         mov     dx,cx               ; Compute port address for the THR
  222. ;       add     dx,thr_8250         ;      and then
  223.         out     dx,al               ;      out the character
  224.  
  225.         jmp     rsint_status        ; Do a status
  226.  
  227. ; Receive a character
  228.  
  229. rsint_recv:
  230.  
  231.         MOV     BX,i_buf_out[BP]   ; Get buffer output pointer
  232.  
  233. rsint_recv_loop:
  234.  
  235.         CMP     i_count[BP],0       ; Anything in buffer?
  236.         JE      rsint_recv_loop     ; No, Wait for it
  237.  
  238. rsint_get_char:
  239.  
  240.         MOV     AL,CS:[BX]          ; Get character from buffer
  241.         PUSH    AX                  ; Save char
  242.         INC     BX                  ; Bump pointer
  243.         DEC     i_count[BP]           ; Dec char count
  244.         MOV     DX,OFFSET i_buf_e  ; Compute end of buffer
  245.         ADD     DX,BP
  246.         CMP     BX,DX               ; Have we wrapped the buffer?
  247.         JL      test_handshake      ;      No.. All done
  248.         MOV     BX,OFFSET i_buf    ;      Yes.. Reset pointer
  249.         ADD     BX,BP
  250. test_handshake:
  251.         cmp     i_count[BP],80H
  252.         jnb     test_full
  253.         mov     ah,flags[BP]
  254.         test    ah,1                ; Did we RTS off?
  255.         jz      test_full           ; No, so don't RTS on
  256. roll_hands:
  257.         mov     DX,CX
  258.         add     DX,mcr_8250
  259.         in      AL,DX
  260.         or      AL,00001011B        ; Raise DTR, RTS  & OUT2
  261.         out     DX,AL
  262.         and     AH,0FEH             ; Remember RTS is on
  263.         mov     flags[BP],AH
  264.  
  265. test_full:
  266.         POP     AX                  ; Restore Char
  267.  
  268.         MOV     i_buf_out[BP],BX   ; Save pointer
  269.         MOV     AH,last_rs[BP]      ; Get last LSR from receive
  270.         AND     AH,0FEH             ; Remove data ready bit
  271.         CMP     i_count[BP],0         ; Anything left in buffer?
  272.         JE      short_exit          ;      Nope so leave
  273.         OR      AH,1                ; Turn on data ready
  274. short_exit:
  275.         JMP     rsint_exit          ;      and go leave
  276.  
  277. ; Status..
  278.  
  279. rsint_status:
  280.  
  281.         MOV     DX,CX               ; Compute port address for the LSR
  282.         ADD     DX,lsr_8250         ;      and then
  283.         IN      AL,DX               ;      get it
  284.  
  285.         AND     AL,0FEH             ; Remove data ready bit
  286.  
  287.         CMP     i_count[BP],0         ; Anything left in buffer?
  288.         JE      rsint_status_nodr   ;      Nope so leave
  289.         OR      AL,1                ; Turn on data ready
  290. rsint_status_nodr:
  291.         MOV     AH,AL               ; Save LSR
  292.  
  293.         MOV     DX,CX               ; Compute port address for the MSR
  294.         ADD     DX,msr_8250         ;      and then
  295.         IN      AL,DX               ;      get it
  296.  
  297.         JMP     rsint_exit          ; All done
  298.  
  299. ; Inquiry
  300. ; (Return AA55H in AX - Just an identification scheme to tell
  301. ;  if this silly driver has been loaded)
  302.  
  303. rsint_inquiry:
  304.  
  305.         MOV     AX,0AA55H
  306.         JMP     rsint_exit          ;      and go leave
  307.  
  308.  
  309. ; send break
  310. rsint_break:
  311.         mov     dx,cx
  312.         add     dx,lcr_8250
  313.         in      al,dx
  314.         mov     bl,al
  315.         mov     al,40h
  316.         out     dx,al
  317.         mov     cx,0
  318.  
  319. bkwait: loop    bkwait
  320.         mov     al,bl
  321.         out     dx,al
  322.         jmp     rsint_exit
  323.  
  324. ; 8250 interrupt handler
  325.  
  326. serint_8250:
  327.  
  328.         PUSH    BP
  329.         PUSH    DX
  330.         PUSH    AX
  331.         PUSH    CX                  ; Save some registers
  332.         PUSH    DI
  333.         xor     bp,bp
  334.  
  335.         MOV     CX,baseaddr[BP]     ; Get base address for chip
  336.  
  337.         MOV     DX,CX               ; Get the IIR
  338.         ADD     DX,iir_8250
  339.         IN      AL,DX
  340.  
  341.         TEST    AL,1                ; Interrupt pending?
  342.         JZ      service
  343.         JMP     serint_8250_exit    ;     No leave...
  344.  
  345. service:
  346.         MOV     DX,CX               ; Get the LSR
  347.         ADD     DX,lsr_8250
  348.         IN      AL,DX
  349.         MOV     last_rs[BP],AL      ; And tuck it away
  350.  
  351.         MOV     DX,CX               ; Get the RBR
  352. ;       ADD     DX,rbr_8250
  353.         IN      AL,DX
  354.         MOV     DI,i_buf_in[BP]    ; Get the buffer pointer
  355.         MOV     CS:[DI],AL          ; Save the character
  356.         INC     DI                  ; Bump pointer and handle wrap
  357.         MOV     AX,OFFSET i_buf_e
  358.         ADD     AX,BP
  359.         CMP     DI,AX
  360.         JL      nowrap
  361.         MOV     DI,OFFSET i_buf
  362.         ADD     DI,BP
  363.  
  364. nowrap:
  365.  
  366.         cmp    i_count[BP],buffer_full
  367.         jb     hand_done
  368.         mov    DX,CX
  369.         add    DX,mcr_8250
  370.         in     al,DX
  371.         and    AL,11111100B         ; Drop DTR & RTS
  372.         out    DX,AL
  373.         mov    ah,flags[BP]
  374.         or     AH,1                 ; Remember RTS is off
  375.         mov    flags[BP],AH
  376.  
  377. hand_done:
  378.  
  379.         CMP     DI,i_buf_out[BP]   ; Overflow of buffer?
  380.         JNE     noover
  381.         OR      last_rs[BP],2       ; Overrun indicate
  382.         JMP     SHORT serint_8250_exit ;  Don't save the updated pointer
  383. noover:
  384.         MOV     i_buf_in[BP],DI    ; Save the updated pointer
  385.         inc     i_count[BP]           ; inc char count
  386.  
  387. serint_8250_exit:
  388.  
  389.         MOV     AL,20H              ; Tell 8259 we are done
  390.         OUT     pic_cmd_port,AL
  391.         POP     DI                  ; Restore registers
  392.         POP     CX
  393.         POP     AX
  394.         POP     DX
  395.         POP     BP
  396.  
  397.         IRET                        ; Exit
  398.  
  399. program_end:
  400.  
  401. ; Main line to initialize.
  402.  
  403.       ASSUME DS: everything
  404.  
  405. ; Constants only needed by initialization
  406.  
  407. P3F8    DB      0       ;1 IF CARD AT 3F8
  408. P2F8    DB      0       ;1 IF CARD AT 2F8
  409.  
  410. HELLO   DB      CR,LF
  411.         DB      'COM1BIOS Driver v1.5',CR,LF
  412.         DB      'Dec 18, 1986 '
  413.         DB      CR,LF,'$'
  414.  
  415. BYE     DB      CR,LF
  416.         DB      'Driver Installed OK!'
  417.         DB      CR,LF,'$'
  418.  
  419. LOADED  DB      CR,LF
  420.         DB      'COM1BIOS already loaded!'
  421.         DB      CR,LF,'$'
  422.  
  423. COM1F   DB      CR,LF
  424.         DB      'COM1: board found at 03F8',CR,LF
  425.         DB      '$'
  426.  
  427. COM2F   DB      CR,LF
  428.         DB      'COM2: board found at 02F8',CR,LF
  429.         DB      '$'
  430.  
  431. NOCOM   DB      CR,LF
  432.         DB      'COM1: board not found.'
  433.         DB      CR,LF
  434.         DB      'Driver NOT installed!',CR,LF
  435.         DB      '$'
  436.  
  437. ; INITIALIZE ROUTINE
  438.  
  439. start:  MOV     AX,CS                 ; Point DS in the right place
  440.         MOV     DS,AX
  441.         CALL    SINON   ;PRINT SIGN ON
  442.  
  443.         MOV     DX,00   ;Check to see if support already loaded
  444.         MOV     AH,04
  445.         INT     14H
  446.         CMP     AX,0AA55H
  447.         JZ      EXIT    ;Must be loaded
  448.  
  449.         CALL    CNFIG   ;CHECK CONFIGURATION
  450.         OR      AX,AX
  451.         JNZ     EREXIT  ;JMP IF ERRORS
  452.  
  453.         CALL    init_vectors    ;SET INTERRUPT VECTORS
  454.  
  455.         CALL    SINOFF          ;PRINT SIGN OFF
  456.         MOV     AL,0            ;set exit code
  457.         MOV     DX,OFFSET program_end
  458.         MOV     CL,4
  459.         SHR     DX,CL
  460.         INC     DX
  461.         MOV     AH,31H
  462.         INT     21H             ; Terminate but stay resident
  463.  
  464. EREXIT: MOV     AL,1            ;set exit code = Error
  465.         MOV     AH,4CH
  466.         INT     21H             ; Terminate and return
  467.  
  468. EXIT:   LEA     DX,LOADED
  469.         MOV     AH,9
  470.         INT     21H
  471.         MOV     AL,0            ;set exit code = Ok
  472.         MOV     AH,4CH
  473.         INT     21H             ; Terminate and return
  474.  
  475.  
  476. ;---------
  477. CNFIG:  CALL    FNDPT           ;Find Ports
  478.         CMP     P3F8,1
  479.         JNE     CNF1
  480.         LEA     DX,COM1F        ;Say COM1 Found
  481.         MOV     AH,9
  482.         INT     21H
  483.  
  484. CNF1:   CMP     P2F8,1
  485.         JNE     CNF2
  486.         LEA     DX,COM2F        ;Say COM2 Found
  487.         MOV     AH,9
  488.         INT     21H
  489.  
  490. CNF2:   CMP     P3F8,1
  491.         JE      CNF3
  492.         LEA     DX,NOCOM        ;Say OOPS
  493.         MOV     AH,9
  494.         INT     21H
  495.  
  496. CNFERR: MOV     AX,0FFFFH       ;Set Error
  497.         RET
  498.  
  499. CNF3:   SUB     AX,AX
  500.         RET
  501.  
  502. ;------------
  503.  
  504. FNDPT:  MOV     DX,03F8H
  505.         CALL    CKPORT
  506.         CMP     BP,0
  507.         JZ      PT2
  508.  
  509.         INC     P3F8
  510.  
  511. PT2:    MOV     DX,02F8H
  512.         CALL    CKPORT
  513.         CMP     BP,0
  514.         JZ      PT3
  515.  
  516.         INC     P2F8
  517.  
  518. PT3:    RET
  519.  
  520.  
  521. ; Check for valid Port
  522. ; Enter with DX containing Port address
  523. ; Exit with BP=Port address if port found  BP=0 if not found
  524.  
  525.  
  526. CKPORT: MOV     BP,DX           ;For return
  527.         MOV     CL,DL           ;Keep DL Handy
  528.  
  529.         ADD     DX,3
  530.         IN      AL,DX           ;Save old LCR in CH
  531.         MOV     CH,AL
  532.  
  533.         MOV     AL,80H          ;Address Divisor Latch
  534.         OUT     DX,AL
  535.         CALL    WAIT
  536.  
  537.         MOV     DL,CL
  538.         IN      AL,DX
  539.         MOV     AH,AL           ;Save old Divisor
  540.         CALL    WAIT
  541.  
  542.         INC     DX
  543.         IN      AL,DX           ;Save old Divisor
  544.         MOV     BX,AX
  545.         CALL    WAIT
  546.  
  547.         MOV     DL,CL
  548.         MOV     AL,55H          ;OUTPUT 55
  549.         OUT     DX,AL
  550.         CALL    WAIT
  551.  
  552.         INC     DX
  553.         MOV     AL,0AAH
  554.         OUT     DX,AL           ;OUTPUT AA
  555.         CALL    WAIT
  556.  
  557.         MOV     DL,CL
  558.         IN      AL,DX           ;Read New Divisor
  559.         MOV     AH,AL
  560.         CALL    WAIT
  561.  
  562.         INC     DX
  563.         IN      AL,DX
  564.         CMP     AX,55AAH        ;DO THEY MATCH?
  565.         JZ      Match
  566.  
  567.         XOR     BP,BP           ;Zero - no match
  568.  
  569. Match:  MOV     DL,CL
  570.         MOV     AL,BH           ;Restore old Divisor
  571.         OUT     DX,AL
  572.         CALL    WAIT
  573.  
  574.         INC     DX
  575.         MOV     AL,BL
  576.         OUT     DX,AL
  577.         CALL    WAIT
  578.  
  579.         INC     DX
  580.         INC     DX              ;and old LCR
  581.         MOV     AL,CH
  582.         OUT     DX,AL
  583.         CALL    WAIT
  584.  
  585. WAIT:   RET
  586.  
  587. ;---------
  588. ;PRINT SIGNON
  589. SINON:  LEA     DX,HELLO
  590.         MOV     AH,9
  591.         INT     21H
  592.         RET
  593.  
  594. ;PRINT SIGNOFF
  595. SINOFF: LEA     DX,BYE
  596.         MOV     AH,9
  597.         INT     21H
  598.         RET
  599.  
  600. ; Now snatch the BIOS comm vector  (Int 14)
  601.  
  602. init_vectors:
  603.  
  604.         MOV     AL,14H
  605.         MOV     AH,35H
  606.         INT     21H
  607.         MOV     old_bios_vector,BX     ;      save old vector
  608.         MOV     old_bios_vector+2,ES
  609.  
  610.         MOV     DX,OFFSET rsint         ; Replace with our vector
  611.         MOV     AL,14H
  612.         MOV     AH,25H
  613.         INT     21H
  614.  
  615. ; Set the hardware interrupt vector
  616.  
  617.         XOR     bp,bp                  ; Get a zero
  618.         MOV     DX,OFFSET serint_8250  ; Get our address
  619.         MOV     AL,hiv[BP]
  620.         MOV     AH,25H
  621.         INT     21H
  622.  
  623. ; Initialize the buffer ring pointers
  624.  
  625.         MOV     AX,OFFSET i_buf  ; Get start of buffer address
  626.         ADD     AX,BP             ; include our offset
  627.         MOV     i_buf_in[BP],AX  ; Put in the buffer pointers
  628.         MOV     i_buf_out[BP],AX ; Put in the buffer pointers
  629.  
  630. ; Set the interrupt registers in the UART and clean things up
  631.  
  632.         CLI                       ; Disable interrupts
  633.  
  634.         IN      AL,pic_mask_port  ; Set up 8259 interupt controller
  635.         AND     AL,int_mask[BP]   ; Enable the interrupts for this device
  636.         OUT     pic_mask_port,AL
  637.  
  638.         MOV     CX,baseaddr[BP]     ; Get base address for chip
  639.  
  640.         MOV     DX,CX             ; Compute port address for the IER
  641.         ADD     DX,ier_8250
  642.         MOV     AL,1              ; Enable data interrupt only
  643.         OUT     DX,AL
  644.  
  645.         MOV     DX,CX             ; Compute port address for the RBR
  646.         ADD     DX,rbr_8250
  647.         IN      AL,DX             ; Read the input buffer and throw it away
  648.  
  649. ; Enable interrupts
  650.  
  651.         STI                        ; Enable CPU to receive interupts
  652.         RET
  653.  
  654. everything ENDS
  655.  
  656.         END foo
  657.